home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / FWStream / FWArDyna.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  17.7 KB  |  511 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWArDyna.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef FWEXCEPT_H
  13. #include "FWExcept.h"
  14. #endif
  15.  
  16. #ifndef FWARDYNA_H
  17. #include "FWArDyna.h"
  18. #endif
  19.  
  20. #ifndef FWPRISTR_H
  21. #include "FWPriStr.h"
  22. #endif
  23.  
  24. #ifndef FWPRIDEB_H
  25. #include "FWPriDeb.h"
  26. #endif
  27.  
  28. #ifndef FWARCOBJ_K
  29. #include "FWArcObj.k"
  30. #endif
  31.  
  32. #ifdef FW_DEBUG
  33. #include <stdio.h>
  34. #endif
  35.  
  36. #include "FWTMap.tpp"
  37.  
  38. #ifdef FW_BUILD_MAC
  39. #pragma segment FWArchiv
  40. #endif
  41.  
  42. //========================================================================================
  43. //    Constants having file scope
  44. //========================================================================================
  45.  
  46. const short kIDOnly = FW_kPrivIDOnly;
  47. const short kIDAndValue = FW_kPrivIDAndValue;
  48.  
  49. const FW_ObjectRegistry_ID kNotInRegistry = FW_kPrivNotInRegistry;
  50. const FW_ObjectRegistry_ID kNULLObjectID = FW_kPrivNULLObjectID;
  51.  
  52. //========================================================================================
  53. //    Keys Matching Function
  54. //========================================================================================
  55.  
  56. static int FW_PrivCompareNames(void* first, void* second);
  57. static int FW_PrivCompareLabels(void* first, void* second);
  58.  
  59. //========================================================================================
  60. //    Template Instantiations
  61. //========================================================================================
  62.  
  63. #ifdef FW_USE_TEMPLATE_PRAGMAS
  64.  
  65. #pragma template_access public
  66. #pragma template FW_TMap<FW_SPrivArcStr, FW_ClassTypeConstant>
  67. #pragma template FW_TMap<FW_ClassTypeConstant, FW_SPrivArcFun>
  68.  
  69. #else
  70.  
  71. template class FW_TMap<FW_SPrivArcStr, FW_ClassTypeConstant>;
  72. template class FW_TMap<FW_ClassTypeConstant, FW_SPrivArcFun>;
  73.  
  74. #endif
  75.  
  76. static void* ClassLabel_Create(FW_CReadableStream& stream, FW_ClassTypeConstant type);
  77. static void ClassLabel_Output(FW_CWritableStream& stream, FW_ClassTypeConstant type, const void *object);
  78.  
  79. FW_ClassTypeConstant kMetaClassTypeConstant = FW_TYPE_CONSTANT('c', 'l', 'a', 's');
  80. FW_CPrivArchiver gFWArchiveMetaClass(kMetaClassTypeConstant, FW_SPrivArcFun(ClassLabel_Create, 0, 0, ClassLabel_Output));
  81.  
  82. //========================================================================================
  83. //    Class FW_CPrivArchiver
  84. //========================================================================================
  85.  
  86. FW_SPrivArchiverGlobals FW_CPrivArchiver::fgGlobals;
  87.  
  88. //----------------------------------------------------------------------------------------
  89. // FW_CArchiveDictionary& FW_CPrivArchiver::GetNameToLabelMap
  90. //----------------------------------------------------------------------------------------
  91.  
  92. FW_CPrivNameToLabelMap& FW_CPrivArchiver::GetNameToLabelMap()
  93. {
  94.     return *GetArchiverGlobals().gNameToLabelMap;
  95. }
  96.  
  97. //----------------------------------------------------------------------------------------
  98. // FW_CArchiveDictionary& FW_CPrivArchiver::GetLabelToIOFunctionMap
  99. //----------------------------------------------------------------------------------------
  100.  
  101. FW_CPrivLabelToIOFunctionMap& FW_CPrivArchiver::GetLabelToIOFunctionMap()
  102. {
  103.     return *GetArchiverGlobals().gLabelToIOFunctionMap;
  104. }
  105.  
  106. //----------------------------------------------------------------------------------------
  107. // FW_CPrivArchiver::GetArchiverGlobals
  108. //----------------------------------------------------------------------------------------
  109.  
  110. FW_SPrivArchiverGlobals& FW_CPrivArchiver::GetArchiverGlobals()
  111. {
  112.     FW_SPrivArchiverGlobals *globals = &fgGlobals;
  113.  
  114.     if (globals->gNameToLabelMap == 0)
  115.         Initialize(*globals);
  116.     return *globals;
  117. }
  118.  
  119. //----------------------------------------------------------------------------------------
  120. // FW_CPrivArchiver::AddNameToLabelPair
  121. //----------------------------------------------------------------------------------------
  122.  
  123. void FW_CPrivArchiver::AddNameToLabelPair(FW_ClassTypeConstant classLabel, const char* className)
  124. {
  125. #ifdef FW_DEBUG
  126.     FW_ASSERT(("Can't register a class as archivable if it doesn't have RTTI.", className != 0));
  127.     FW_CPrivNameToLabelPair* pair = GetNameToLabelMap().Find(FW_SPrivArcStr(className));
  128.     if (pair !=0)
  129.     {
  130.         char buffer[256];
  131.         sprintf(buffer, "Class %s has already been registered as archivable!", className);
  132.         FW_DEBUG_MESSAGE(buffer);
  133.     }
  134. #endif
  135.  
  136.     GetNameToLabelMap()[FW_SPrivArcStr(className)] = classLabel;
  137. }
  138.  
  139. //----------------------------------------------------------------------------------------
  140. // FW_CPrivArchiver::AddLabelToIOFunctionPair
  141. //----------------------------------------------------------------------------------------
  142.  
  143. void FW_CPrivArchiver::AddLabelToIOFunctionPair(FW_ClassTypeConstant classLabel, const FW_SPrivArcFun& functions)
  144. {
  145. #ifdef FW_DEBUG
  146.     FW_ASSERT(GetLabelToIOFunctionMap().Find(classLabel) == 0);
  147. #endif
  148.  
  149.     GetLabelToIOFunctionMap()[classLabel] = functions;
  150. }
  151.  
  152. //----------------------------------------------------------------------------------------
  153. // FW_CPrivArchiver::FW_CPrivArchiver
  154. //----------------------------------------------------------------------------------------
  155.  
  156. FW_CPrivArchiver::FW_CPrivArchiver(FW_ClassTypeConstant classLabel,
  157.                                 const char* className,
  158.                                 const FW_SPrivArcFun& functions)
  159. {
  160.     AddNameToLabelPair(classLabel, className);
  161.     AddLabelToIOFunctionPair(classLabel, functions);
  162. }
  163.  
  164. //----------------------------------------------------------------------------------------
  165. // FW_CPrivArchiver::FW_CPrivArchiver
  166. //----------------------------------------------------------------------------------------
  167.  
  168. FW_CPrivArchiver::FW_CPrivArchiver(FW_ClassTypeConstant classLabel,
  169.                                 const FW_SPrivArcFun& functions)
  170. {
  171.     AddLabelToIOFunctionPair(classLabel, functions);
  172. }
  173.  
  174. //----------------------------------------------------------------------------------------
  175. // FW_CPrivArchiver::PreregisterSpecialObject
  176. //----------------------------------------------------------------------------------------
  177.  
  178. void FW_CPrivArchiver::PreregisterRuntimeObject(
  179.                                     FW_OObjectRegistry* registry,
  180.                                     const void* object,
  181.                                     FW_ObjectRegistry_ID objectID)
  182. {
  183.     FW_SOMEnvironment ev;
  184.     registry->RegisterObjectAndID(ev, (void*) object, objectID);
  185. }
  186.  
  187. //----------------------------------------------------------------------------------------
  188. // ClassLabel_Create
  189. //
  190. // Notes:
  191. //    1.    You may have expected this method to return a pointer to the class label. Doing
  192. //        so, however, would result in two problems. First, the pointer returned would have
  193. //        to be to a buffer allocated by this method and who would delete it? Second, even
  194. //        if a pointer to a class label was returned, by returning a FW_SPrivArcFun
  195. //        pointer, we only have to map a particular class label once (via the map
  196. //        'gLabelToIOFunctionMap') for the entire 'readableStream'. That is,
  197. //        if there are "n" occurrences of a particular class label in a 'readableStream',
  198. //        one reference to 'gLabelToIOFunctionMap' is made instead of "n".
  199. //----------------------------------------------------------------------------------------
  200.  
  201. static void* ClassLabel_Create(FW_CReadableStream& stream, FW_ClassTypeConstant type)
  202. {
  203. FW_UNUSED(type);
  204.     // Read the class label of the object from the archive.
  205.     FW_ClassTypeConstant label;
  206.     stream >> label;
  207.     FW_CPrivLabelToIOFunctionPair* pair = FW_CPrivArchiver::LookupArchivingFunctions(label);
  208.     if (pair == NULL)
  209.     {
  210.         // If you get this assertion there is a good chance that it's because you loaded
  211.         // views from resources and forgot to use the macro FW_DO_NOT_DEAD_STRIP in your
  212.         // code for those classes that are not referenced anywhere else, for instance 
  213.         // FW_DO_NOT_DEAD_STRIP(FW_CGrowBox).   See the ODF samples.
  214. #ifdef FW_DEBUG
  215.         char msg[255];
  216.         char* c = (char*)&label;
  217.         sprintf(msg, "'%c%c%c%c' class not registered for archiving. Forgot FW_DO_NOT_DEAD_STRIP ?", c[0],c[1],c[2],c[3]);
  218.         FW_DEBUG_MESSAGE(msg);
  219. #endif
  220.     }
  221.     return pair;
  222. }
  223.  
  224. //----------------------------------------------------------------------------------------
  225. // ClassLabel_Output
  226. //----------------------------------------------------------------------------------------
  227.  
  228. static void ClassLabel_Output(FW_CWritableStream& stream, FW_ClassTypeConstant type, const void *object)
  229. {
  230. FW_UNUSED(type);
  231.     FW_CPrivLabelToIOFunctionPair* item = (FW_CPrivLabelToIOFunctionPair*) object;
  232.     FW_ClassTypeConstant label = item->fKey;
  233.     stream << label;
  234. }
  235.  
  236. //----------------------------------------------------------------------------------------
  237. // FW_CPrivArchiver::LookupArchivingFunctions
  238. //----------------------------------------------------------------------------------------
  239.  
  240. FW_CPrivLabelToIOFunctionPair* FW_CPrivArchiver::LookupArchivingFunctions(FW_ClassTypeConstant label)
  241. {
  242.     static FW_CPrivLabelToIOFunctionPair* gCachedMetaPair = GetLabelToIOFunctionMap().Find(kMetaClassTypeConstant);
  243.     FW_CPrivLabelToIOFunctionPair* result = 0;
  244.     if (kMetaClassTypeConstant == label)
  245.         result = gCachedMetaPair;
  246.     else
  247.         result = GetLabelToIOFunctionMap().Find(label);
  248.     return result;
  249. }
  250.  
  251. //----------------------------------------------------------------------------------------
  252. // FW_CPrivArchiver::CreateObject
  253. //----------------------------------------------------------------------------------------
  254.  
  255. void FW_CPrivArchiver::CreateObject(FW_CReadableStream& readableStream, void*& object)
  256. {
  257.     FW_CPrivLabelToIOFunctionPair* pair = (FW_CPrivLabelToIOFunctionPair*) 
  258.         PrivCreateObject(readableStream, kMetaClassTypeConstant);
  259.     object = PrivCreateObject(readableStream, pair ? pair->fKey : FW_kNullTypeConstant);
  260. }
  261.  
  262. //----------------------------------------------------------------------------------------
  263. // FW_CPrivArchiver::OutputObject
  264. //----------------------------------------------------------------------------------------
  265.  
  266. void FW_CPrivArchiver::OutputObject(FW_CWritableStream& writableStream,
  267.                                        const void* object,
  268.                                        const char* className)
  269. {
  270.     if (!object)
  271.     {
  272.         writableStream << kIDOnly << kNULLObjectID;    // Null class
  273.         writableStream << kIDOnly << kNULLObjectID;    // Null object
  274.     }
  275.     else
  276.     {
  277.         FW_SPrivArcStr tempName(className);
  278.         FW_ASSERT(GetNameToLabelMap().Find(tempName));
  279.         FW_ClassTypeConstant label = GetNameToLabelMap()[tempName];
  280.     
  281.         FW_CPrivLabelToIOFunctionPair* item = GetLabelToIOFunctionMap().Find(label);
  282.         FW_ASSERT(item);
  283.     
  284.         // Write the class label out to the archive.
  285.         PrivOutputObject(writableStream, kMetaClassTypeConstant, item);
  286.  
  287.         // Write the 'object' data out to the archive.
  288.         PrivOutputObject(writableStream, label, object);
  289.     }
  290. }
  291.  
  292. //----------------------------------------------------------------------------------------
  293. // FW_CPrivArchiver::Initialize
  294. //----------------------------------------------------------------------------------------
  295.  
  296. void FW_CPrivArchiver::Initialize(FW_SPrivArchiverGlobals& globals)
  297. {
  298.     globals.gNameToLabelMap = 
  299.             new FW_CPrivNameToLabelMap(FW_PrivCompareNames);
  300.     globals.gLabelToIOFunctionMap = 
  301.             new FW_CPrivLabelToIOFunctionMap(FW_PrivCompareLabels);
  302. }
  303.  
  304. //----------------------------------------------------------------------------------------
  305. // FW_CPrivArchiver::Terminate
  306. //----------------------------------------------------------------------------------------
  307.  
  308. void FW_CPrivArchiver::Terminate()
  309. {
  310.     FW_SPrivArchiverGlobals& globals = GetArchiverGlobals();
  311.     delete globals.gNameToLabelMap;
  312.     delete globals.gLabelToIOFunctionMap;
  313. }
  314.  
  315. //========================================================================================
  316. //    Struct FW_SPrivArcStr
  317. //========================================================================================
  318.  
  319. //----------------------------------------------------------------------------------------
  320. // FW_SPrivArcStr::FW_SPrivArcStr
  321. //----------------------------------------------------------------------------------------
  322.  
  323. FW_SPrivArcStr::FW_SPrivArcStr(const char* string) :
  324.     fString(string)
  325. {
  326.     FW_ASSERT(this->fString != NULL);
  327. }
  328.  
  329. //========================================================================================
  330. //    Struct FW_SPrivArcFun
  331. //========================================================================================
  332.  
  333. //----------------------------------------------------------------------------------------
  334. // FW_SPrivArcFun::FW_SPrivArcFun
  335. //----------------------------------------------------------------------------------------
  336.  
  337. FW_SPrivArcFun::FW_SPrivArcFun(Create create,
  338.                                 Initialize initialize,
  339.                                 Destroy destroy,
  340.                                 Output output) :
  341.     fCreateFunction(create),
  342.     fInitializeFunction(initialize),
  343.     fDestroyFunction(destroy),
  344.     fOutputFunction(output)
  345. {
  346. #ifdef FW_DEBUG
  347.     if (fInitializeFunction != NULL)
  348.         FW_ASSERT(("If an initialize function is registered, a destroy function must be too", fDestroyFunction != NULL));
  349. #endif
  350. }
  351.  
  352. //========================================================================================
  353. //    Keys Matching Function
  354. //========================================================================================
  355.  
  356. //----------------------------------------------------------------------------------------
  357. //    FW_PrivKeysMatchProc
  358. //----------------------------------------------------------------------------------------
  359.  
  360. int FW_PrivCompareNames(void* k1, void* k2)
  361. {
  362.     FW_CPrivNameToLabelPair* key1 = (FW_CPrivNameToLabelPair*) k1;
  363.     FW_CPrivNameToLabelPair* key2 = (FW_CPrivNameToLabelPair*) k2;
  364.     return FW_PrimitiveStringCompare(key1->fKey.fString, key2->fKey.fString);
  365. }
  366.  
  367. int FW_PrivCompareLabels(void* k1, void* k2)
  368. {
  369.     FW_CPrivLabelToIOFunctionPair* key1 = (FW_CPrivLabelToIOFunctionPair*) k1;
  370.     FW_CPrivLabelToIOFunctionPair* key2 = (FW_CPrivLabelToIOFunctionPair*) k2;
  371.     if (key1->fKey < key2->fKey)
  372.         return -1;
  373.     else if (key1->fKey == key2->fKey)
  374.         return 0;
  375.     else
  376.         return 1;
  377. }
  378.  
  379. //----------------------------------------------------------------------------------------
  380. // FW_CPrivArchiver::PrivCreateObject
  381. //----------------------------------------------------------------------------------------
  382.  
  383. void* FW_CPrivArchiver::PrivCreateObject(FW_CReadableStream& readableStream, 
  384.                                         FW_ClassTypeConstant classLabel)
  385. {
  386.     FW_SOMEnvironment ev;
  387.     void* objectPtr = NULL;
  388.     FW_OObjectRegistry* registry = readableStream.GetRegistry();
  389.  
  390.     short byValue;
  391.     FW_ObjectRegistry_ID id;
  392.  
  393.     readableStream >> byValue >> id;
  394.  
  395.     switch (byValue)
  396.     {
  397.         case kIDOnly:
  398.         {
  399.             if (id == FW_kPrivNULLObjectID)
  400.                 objectPtr = NULL;
  401.             else
  402.             {
  403.                 objectPtr = registry->LookupByID(ev, id);
  404.                 FW_ASSERT(("Object registry ID was not found in registry", objectPtr != NULL));
  405.                 // If the above assertion fails, the stream is probably corrupt.
  406.                 // However, one should check to see (using a debugger) if the id is a negative
  407.                 // value.  If so, then the stream may have a reference to a preregistered object,
  408.                 // but for some reason the object wasn't preregistered at runtime.
  409.                 if (objectPtr == NULL)
  410.                     FW_Failure(FW_xCorruptArchiveStream);
  411.             }
  412.             break;
  413.         }
  414.         case kIDAndValue:
  415.         {
  416.             // We allow for two-step construction here.
  417.             // 1) Allocate raw memory and possibly do minimal initialization
  418.             // 2) Finish full initialization
  419.             // Object is registered between steps 1 and 2. Object objects
  420.             // created during step 2 can have references back to this object.
  421.             FW_CPrivLabelToIOFunctionPair* pair = LookupArchivingFunctions(classLabel);
  422.             if (pair == NULL)
  423.                 pair = LookupArchivingFunctions(FW_kWildCardLabel);
  424.             FW_ASSERT(("No registered archiving functions for class label", pair != NULL));
  425.             if (pair == NULL)
  426.                 FW_Failure(FW_xCorruptArchiveStream);
  427.  
  428.             FW_SPrivArcFun* archivingFunctions = &pair->fValue;
  429.             FW_SPrivArcFun::Create create = archivingFunctions->fCreateFunction;
  430.             FW_ASSERT(("Attempt to create object from stream with NULL create function", create != NULL));
  431.             if (create == NULL)
  432.                 FW_Failure(FW_xCorruptArchiveStream);
  433.             
  434.             objectPtr = create(readableStream, classLabel);
  435.             FW_ASSERT(objectPtr != NULL);
  436.             if (objectPtr == NULL)
  437.                 FW_Failure(FW_xCorruptArchiveStream);
  438.  
  439.             if (id != kNotInRegistry)
  440.                 registry->RegisterObjectAndID(ev, objectPtr, id);
  441.  
  442.             FW_SPrivArcFun::Initialize initialize = archivingFunctions->fInitializeFunction;
  443.             if (initialize != 0)
  444.             {
  445.                 FW_SPrivArcFun::Destroy destroy = archivingFunctions->fDestroyFunction;
  446.                 FW_ASSERT(destroy != NULL);
  447.                 if (destroy == NULL)
  448.                     FW_Failure(FW_xCorruptArchiveStream);
  449.                 FW_TRY
  450.                 {
  451.                     initialize(readableStream, classLabel, objectPtr);
  452.                 }
  453.                 FW_CATCH_BEGIN
  454.                 FW_CATCH_EVERYTHING()
  455.                 {
  456.                     destroy(objectPtr, classLabel);
  457.                     FW_THROW_SAME();
  458.                 }
  459.                 FW_CATCH_END
  460.             }
  461.             break;
  462.         }
  463.         default:
  464.         {
  465.             FW_ASSERT(false);
  466.             FW_Failure(FW_xCorruptArchiveStream);
  467.             break;
  468.         }
  469.     }
  470.  
  471.     return objectPtr;
  472. }
  473.  
  474. //----------------------------------------------------------------------------------------
  475. // FW_CPrivArchiver::PrivOutputObject
  476. //----------------------------------------------------------------------------------------
  477.  
  478. void FW_CPrivArchiver::PrivOutputObject(FW_CWritableStream& writableStream, 
  479.                                         FW_ClassTypeConstant classLabel,
  480.                                         const void* object)
  481. {
  482.     FW_SOMEnvironment ev;
  483.  
  484.     FW_OObjectRegistry* registry = writableStream.GetRegistry();
  485.     FW_ObjectRegistry_ID id = registry->LookupByObject(ev, (void*) object);
  486.  
  487.     if (id == kNotInRegistry)
  488.     {
  489.         FW_CPrivLabelToIOFunctionPair* pair = LookupArchivingFunctions(classLabel);
  490.         if (pair == NULL)
  491.             pair = LookupArchivingFunctions(FW_kWildCardLabel);
  492.         FW_ASSERT(("No registered archiving functions for class label", pair != NULL));
  493.         if (pair == NULL)
  494.             FW_Failure(FW_xCorruptArchiveStream);
  495.     
  496.         FW_SPrivArcFun* archivingFunctions = &pair->fValue;
  497.         FW_SPrivArcFun::Output output = archivingFunctions->fOutputFunction;
  498.         FW_ASSERT(output != NULL);
  499.         if (output == NULL)
  500.             FW_Failure(FW_xCorruptArchiveStream);
  501.     
  502.         id = registry->RegisterObject(ev, (void*) object);
  503.         writableStream << kIDAndValue << id;
  504.         output(writableStream, classLabel, object);
  505.     }
  506.     else
  507.     {
  508.         writableStream << kIDOnly << id;
  509.     }
  510. }
  511.